package controllers

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"go-admin-official/guard"
	"go-admin-official/models"
	"go-admin-official/modules/auth"
	"go-admin-official/modules/database"
	"go-admin-official/modules/pay"
	"io/ioutil"
	"net/http"
	"net/url"
)

func CreateProductBuyOrder(ctx *gin.Context) {

	param := guard.GetCreateOrderParam(ctx)
	user := auth.Auth(ctx)

	// 创建订单，确定使用支付宝/微信
	order, good, err := models.Order().New(param, user.Id)

	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
		return
	}

	// 返回支付配置，前端生成支付二维码
	code := ""
	title := ""

	if param.IsPlugin() {
		plugin := models.Plugin().Find(good.ProductId).Translate(param.Lang)
		title = "购买插件《" + plugin.Title + "》"
	} else if param.IsTheme() {
		theme := models.Theme().Find(good.ProductId).Translate(param.Lang)
		title = "购买主题《" + theme.Title + "》"
	}

	if param.IsAlipay() {
		code, err = pay.GetWebAliPayConfig(order.OrderNo, title, "0.03")
	} else if param.IsWechatPay() {
		code, err = pay.GetWxpayCode(order.OrderNo, title, "0.03")
	}

	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
		return
	}

	err = order.UpdateSubmit()

	if err != nil {
		ctx.JSON(http.StatusOK, gin.H{
			"code": 500,
			"msg":  err.Error(),
		})
		return
	}

	ctx.JSON(http.StatusOK, gin.H{
		"code": 0,
		"data": gin.H{
			"qrcode": url.QueryEscape(code),
			"no":     order.OrderNo,
			"title":  title,
			"price":  good.PriceStr(),
		},
	})
}

func handlerPayCallback(ctx *gin.Context, orderNo, payTradeNo, result string, tradeResult bool) {

	order := models.Order().FindByOrderNo(orderNo)

	// 确认订单号正确, 确认订单未被处理
	if order.IsEmpty() || order.HasProceed() {
		ctx.String(http.StatusOK, "fail")
		return
	}

	err, _ := database.WithTransaction(func(tx *database.SqlTx) (e error, i map[string]interface{}) {

		if tradeResult {

			// 根据结果修改订单
			updateOrderSuccessError := models.Order().WithTx(tx).
				WithID(order.Id).UpdateSuccess(result, orderNo, payTradeNo)

			if updateOrderSuccessError != nil {
				fmt.Println("update order success error: ", updateOrderSuccessError)
				return updateOrderSuccessError, nil
			}

			var insertAccountLogErr error

			good := models.Goods().Find(order.ProductId)
			user := models.Users().Find(order.UserId)

			// 增加账户记录
			if good.IsPlugin() {
				insertAccountLogErr = models.AccountLog().WithTx(tx).
					InsertBuyPluginLog(order.UserId, order.Amount, user.Amount)
			} else {
				insertAccountLogErr = models.AccountLog().WithTx(tx).
					InsertBuyThemeLog(order.UserId, order.Amount, user.Amount)
			}

			if insertAccountLogErr != nil {
				fmt.Println("insert account log error: ", insertAccountLogErr)
				return insertAccountLogErr, nil
			}

			// 增加购买记录
			var insertBuyRecordError error
			if good.IsPlugin() {
				insertBuyRecordError = models.UserBuyPlugins().WithTx(tx).
					Insert(good.ProductId, order.Id, order.UserId, order.ProductId, good.ProductType)
			} else if good.IsTheme() {
				// TODO:
			}

			if insertBuyRecordError != nil {
				fmt.Println("insert buy plugin record error: ", insertBuyRecordError)
				return insertBuyRecordError, nil
			}

			// 增加插件购买数量
			addBuyNumError := models.Plugin().WithTx(tx).WithID(order.ProductId).AddBuyNum()

			if addBuyNumError != nil {
				fmt.Println("add plugin buy num error: ", addBuyNumError)
				return addBuyNumError, nil
			}
		} else {
			updateOrderFailError := models.Order().WithTx(tx).WithID(order.Id).UpdateFail()

			if updateOrderFailError != nil {
				fmt.Println("update order fail error: ", updateOrderFailError)
				return updateOrderFailError, nil
			}
		}

		return nil, nil
	})

	if err != nil {
		ctx.String(http.StatusOK, "fail")
		return
	}

	ctx.String(http.StatusOK, "ok")
}

func PayCallback(ctx *gin.Context) {
	orderNo, payTradeNo, result, tradeResult, err := pay.GetWxNotifyReturnMsg(ctx)

	if err != nil {
		ctx.String(http.StatusOK, "fail")
		return
	}

	handlerPayCallback(ctx, orderNo, payTradeNo, result, tradeResult)
}

func AliPayCallback(ctx *gin.Context) {

	var (
		orderNo     = ctx.PostForm("out_trade_no")
		payTradeNo  = ctx.PostForm("trade_no")
		tradeStatus = ctx.PostForm("trade_status")
		tradeResult = tradeStatus == "TRADE_SUCCESS"
	)

	body, _ := ioutil.ReadAll(ctx.Request.Body)
	handlerPayCallback(ctx, orderNo, payTradeNo, string(body), tradeResult)
}

func PayResult(ctx *gin.Context) {

	// 轮询获取支付结果
	no := ctx.Query("no")
	order := models.Order().FindByOrderNo(no)
	msg := ""
	downloadURL := ""

	// 支付成功
	if order.PaySuccess() {
		msg = "ok"
		downloadURL = models.Plugin().Find(order.ProductId).GetDownloadURL()
	}

	// 支付失败
	if order.PayFail() {
		msg = "支付失败"
	}

	ctx.JSON(http.StatusOK, gin.H{
		"code": 0,
		"data": gin.H{
			"result": order.State,
			"msg":    msg,
			"url":    downloadURL,
		},
	})
}
